home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #21 (Jun 87) / format source / SCSI.a < prev    next >
Text File  |  1987-05-07  |  25KB  |  810 lines

  1. ;*********************** File: SCSI.a *************************
  2. ;**************************************************************
  3. ;
  4. ; This file contains all the items in the SCSI menu.  It also
  5. ; contains the SCSI primatives for comunication with SCSI hard 
  6. ; disks.  
  7. ;
  8. ; Note: All the symbols that are declared or imported before 
  9. ; start of the first module (PROC, MAIN or RECORD) are defined
  10. ; for all modules in this file.  Forward references to other
  11. ; modules in a file must be imported. 
  12.  
  13.     INCLUDE        'FormatEqu.a'
  14.     LOAD        'Traps.d'
  15.     LOAD        'ToolEqu.d'
  16.     LOAD        'SysEqu.d'
  17.     LOAD        'QuickEqu.d'
  18.     LOAD        'SCSIEqu.d'
  19.  
  20.     EXPORT    (Res,Last_Cmd,CompStat,CompMsg):DATA
  21.     EXPORT    (BadB_Num):DATA
  22.     
  23. Addr        ds.w    1    ;address of hard disk
  24. Heads        ds.l    1    ;number of heads on hard disk
  25. Cyls        ds.l    1    ;number of cylinders on hard disk
  26. WrtPreComp    ds.l    1    ;cylinder to start write precompensation
  27. RedWrtCur    ds.l    1    ;cylinder to start reduced write current
  28. Interleave    ds.w    1    ;interleave number to be used
  29. StepCode    ds.w    1    ;type of step pulse used
  30.     
  31. CompStat    ds.w    1    ;status from _SCSIComplete
  32. CompMsg        ds.w    1    ;message from _SCSIComplete
  33.     
  34. Res            ds.w    1    ;result from SCSI commands    
  35. Last_Cmd    ds.w    1    ;last command executed
  36.  
  37. BadB_Num    ds.l    1                ;total number of bad blocks
  38.     IMPORT    (DialogPort,ItemType,ItemHandle,ItemRect):DATA
  39.     IMPORT    (EventLoop,DefButton,RadioHiLite):CODE
  40.     IMPORT    (CountOff,ExtractNumb,SortBuff,OutBuff):CODE
  41.     IMPORT    (ErrorProc,ClearBuff):CODE
  42.     IMPORT    (DialogBuff,ButtonHit):DATA
  43.     IMPORT    (StrBuff1,StrBuff2,StrBuff3,StrBuff4):DATA
  44.     
  45. Buffers        RECORD    EXPORT
  46.     EXPORT    (CommandBuff,PseudoProg,ParamBuff):DATA
  47.     EXPORT    (BadB_List,BadB_Out):DATA
  48.     ALIGN    2
  49.     
  50. CommandBuff    ds.b    CBuffLen        ;buffer for SCSI commands
  51. PseudoProg    ds.b    PProgLen        ;buffer for pseudo program
  52. ParamBuff    ds.b    ParamBuffLen    ;buffer for parameters
  53. BadB_List    ds.l    MaxBBListLen    ;buffer area for entering and 
  54.                                         ;sorting bad blocks
  55. BadB_Out    ds.l    MaxBBOutLen        ;buffer area for output to
  56.                                         ;to the disk drive
  57.  
  58.     ENDR
  59.     
  60. ; PROC    SelAddrProc
  61. ;
  62. ; This procedure gets the address of the device to be formatted
  63. ; from the user. It then tests to see if the device is connected
  64. ; and if the device is ready to be formatted. If either of these
  65. ; are false, it jumps to ErrorProc (error handling procedure).
  66.  
  67. SelAddrProc    PROC    EXPORT
  68.     IMPORT    (Hd_Select,HD_TestUnit,HD_Discon):CODE
  69.     IMPORT    (UnHiLite,ResetDisk):CODE
  70.     
  71.     clr.l    -(A7)                ;space for pointer to dialog
  72.     move.w    #SelAddrRN,-(A7)    ;select address dialog resource#
  73.     pea        DialogBuff(A5)        ;push pointer to dialog storage
  74.     move.l    #-1,-(A7)            ;make dialog top most window
  75.     _GetNewDialog
  76.     
  77.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and 
  78.                                     ;leave a copy on the stack  the
  79.                                     ;for call to _SetPort
  80.     _SetPort
  81.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  82.     jsr        DefButton            ;make default = "Select" button
  83.     
  84.     move.w    #10,D0                ;make Mac's address grey
  85.     jsr        UnHiLite
  86.     
  87. ; Register ussage:
  88. ;    D0    Radio button that was selected, now must be unselected
  89. ;    D1    Radio button that was just clicked on; to be selected
  90.  
  91. ; Initialize D0 and D3 for first call to RadioHiLite.  D0=0 
  92. ; is flag for no radio button to deselect.  D1=3 is to set the
  93. ; default SCSI address = 0.
  94.     clr.l    D0
  95.     moveq.l    #3,D7                
  96.      
  97.      
  98. NotYet
  99.     move.w    D7,D1                ;update D1 (pass to RadioHiLite)
  100.     jsr        RadioHiLite        ;change radio button selected
  101.     clr.l    -(A7)            ;use standard filter proc function
  102.     pea        ButtonHit(A5)
  103.     _ModalDialog
  104.     cmpi.w    #2,ButtonHit(A5)    ;was select or cancel button hit
  105.     ble        EndDialog            ;yes, so close up dialog
  106.     move.l    D7,D0                ;D0 = id of old radio button
  107.     move.w    ButtonHit(A5),D7    ;D7 = id of new radio button
  108.     bra.s    NotYet                ;loop back for next mouse down
  109.     
  110. EndDialog
  111.     move.l    DialogPort(A5),-(A7)    ;pass address of Dialog Rec
  112.     _CloseDialog                ;close dialog
  113.     
  114.     cmpi.w    #2,ButtonHit(A5)    ;was ok button hit
  115.     blt        Continue            ;yes
  116.     jmp        EventLoop            ;no, go get next event
  117.  
  118. Continue
  119.     subq.w    #3,D7                ;D7 = last radio button hit, so
  120.                                     ;subtract item # for radio
  121.                                     ;button "0"
  122.     move.w    D7,Addr(A5)            ;D7 now equals address selected
  123.     
  124.     jsr        ResetDisk            ;reset SCSI bus
  125.     tst.w    Res(A5)                ;did we succeed
  126.     bne        ToErrorProc            ;no, go handle error
  127.  
  128. ; This next block of code, though the end of this procedure, is
  129. ; an example of how all SCSI commands are done.  You can replace
  130. ; the SCSI command Test Unit Ready with any other SCSI command.
  131. ; The Mode Select and Format Unit commands used in FormatProc 
  132. ; differ only in that data is transfered after the command.
  133.  
  134.  
  135. ; First we get control of the bus and select the target device.
  136.     jsr        HD_Select            ;go get control of bus and
  137.                                     ;select device
  138.     tst.w    Res(A5)                ;did we succeed
  139.     bne        ToErrorProc            ;no, go handle error
  140.  
  141. ; Second, we clear the buffer we use to construct the SCSI
  142. ; command in.
  143.     lea    CommandBuff(A5),A0        ;pass address of buffer in A0
  144.     move.l    #CBuffLen,D0        ;pass buffer size in D0
  145.     jsr        ClearBuff            ;clear buffer
  146.  
  147. ; Third, we construct the command.  This one has no parameters
  148. ; in the CDB (Command Desciption Block), so we only have to move
  149. ; the SCSI OP code into the CDB.
  150.  
  151.     move.b    #TestUReady,CommandBuff(A5)    ;move OP code into byte
  152.                                             ;1 of the CDB
  153.     clr.w    -(A7)                ;clear space for trap result
  154.     pea        CommandBuff(A5)        ;pass address of CDB
  155.     move.w    #CommLenS,-(A7)        ;pass length of command. This is
  156.                                     ;a class 0 SCSI command, so
  157.                                     ;the length is 6 bytes.
  158.  
  159. ; Fourth, we send the command and test if it succeded.
  160.     _SCSICmd                    ;send command to target
  161.     
  162.     move.w    #TestUReady,Last_Cmd(A5)    ;store command id
  163.     move.w    (A7)+,Res(A5)        ;test result, was there an error        
  164.     bne        ToErrorProc            ;yes go to error proc
  165.  
  166. ; Then, we wait for the target device send the Status and
  167. ; Message bytes.  The target device will then release the Mac.
  168.     move.l    #10,D0                ;pass number of ticks to wait
  169.     jsr        HD_Discon            ;proc that handles _SCSIComplete
  170.     tst.w    Res(A5)                ;SCSI Protocal Error?
  171.     bne        ToErrorProc            ;yes, go handle display error
  172.  
  173. ; Lastly, we test the Status byte returned by _SCSIComplete.  
  174. ; This is the SCSI command result code.  It will tell us about
  175. ; the drives condition and if it is ready to be formated.
  176.     move.w    #TestUReady,Last_Cmd(A5)    ;store command id for 
  177.                                             ;error handling proc
  178.     cmp.w    #3,CompStat(A5)        ;is there a Write Fault?
  179.     beq        ToErrorProc            ;yes, go to error handling proc
  180.     cmp.w    #4,CompStat(A5)        ;is the Drive Not Ready?
  181.     beq        ToErrorProc            ;yes, go to error handling proc
  182.     cmp.w    #20,CompStat(A5)    ;is this SCSI command supported?
  183.     beq        ToErrorProc            ;no, go to error handling proc
  184.     
  185.     jmp        EventLoop
  186.  
  187. ToErrorProc
  188.     jmp        ErrorProc
  189.     
  190.     EndProc
  191.  
  192. ; PROC ParamProc
  193. ;
  194. ; We give the user is given dialog box to input parameters used
  195. ; for  formatting drive. We then extract the values from the
  196. ; TextEdit fields and place the hex values in the appropiate
  197. ; global variables.  All values are checked against maximum 
  198. ; values to make sure they are reasonable.
  199.  
  200. ParamProc    PROC    EXPORT
  201.  
  202.     clr.l    -(A7)                ;space for pointer to dialog
  203.     move.w    #ParamRN,-(A7)        ;parameter dialog resource numb.
  204.     pea        DialogBuff(A5)        ;push pointer to dialog storage
  205.     move.l    #-1,-(A7)            ;dialog on top of all windows
  206.     _GetNewDialog
  207.     
  208.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and 
  209.                                     ;leave copy on stack for 
  210.                                     ;call to _SetPort
  211.     _SetPort
  212.     
  213.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  214.     jsr        DefButton            ;make "OK" button the default
  215. ; Now we set up our dialog box. First two calls to RadioHiLite
  216. ; have D0=0 as a flag for no radio button to unselect
  217. ; Register ussage:
  218. ;    D0    Radio button that was selected, now must be unselected
  219. ;    D1    Radio button that was just clicked on; to be selected
  220. ;    D6    Interleave Radio Button that is currently selected
  221. ;    D7    Step Rate Radio Button that is currently selected
  222.     moveq.l    #3,D6                ;default interleave = 1:1
  223.     moveq.l    #7,D7                ;default step pulse = 3 msec
  224.  
  225. ; High light default interleave and step pulse radio buttons.
  226.     move.w    D6,D1                
  227.     clr.w    D0
  228.     jsr        RadioHiLite
  229.     clr.w    D0
  230.     move.w    D7,D1
  231.     jsr        RadioHiLite
  232.      
  233.      
  234. NotYet
  235.     clr.l    -(A7)            ;use standard filter proc function
  236.     pea        ButtonHit(A5)    ;push address of storage for item#
  237.     _ModalDialog
  238.     move.w    ButtonHit(A5),D1    ;move item number to D1
  239.     cmpi.w    #2,D1                ;was OK or Cancel selected?
  240.     ble        EndDialog            ;yes, go close up dialog
  241.     cmpi.w    #9,D1                ;was text edit item hit
  242.     bgt        NotYet                ;yes, loop back for next event
  243.     cmpi.w    #6,D1            ;was interleave radio button hit
  244.     bgt        StepRate        ;no, must be step rate radio button
  245.  
  246. ; Interleave radio button was selected. Update D6 and select
  247. ; the correct radio button.
  248.     move.w    D6,D0            
  249.     move.w    D1,D6            
  250.     jsr        RadioHiLite
  251.     bra.s    NotYet
  252.     
  253. ; Step rate radio button was selected. Update D7 and select
  254. ; the correct radio button.
  255.     StepRate:
  256.     move.w    D7,D0
  257.     move.w    D1,D7
  258.     jsr        RadioHiLite
  259.     bra        NotYet
  260.             
  261. EndDialog
  262.     
  263.     cmpi.w    #2,ButtonHit(A5)    ;was "Cancel" selected?
  264.     blt        Continue            ;no
  265.     bra        exit                ;yes, so exit
  266. ; "OK" button selected so we can update the global variables
  267. ; that contain the step code and the interleave values.
  268. Continue                        
  269.     subq.w    #2,D6
  270.     move.w    D6,Interleave(A5)
  271.     subq.w    #7,D7
  272.     move.w    D7,StepCode(A5)
  273.  
  274. ; For each of the TextEdit fields we place the address of the
  275. ; global variable in A3, the item # in D0 and the maximum value
  276. ; in D3.  We then call ExtractNumb to get the hex, insure that
  277. ; it is not over the maximum value, and place the hex number in
  278. ; the global variable.
  279.     lea        Heads(A5),A3        ;extract number of heads from 
  280.     move.l    #10,D0                    ;item number 10
  281.     move.l    #MaxHeads,D3
  282.     jsr        ExtractNumb
  283.  
  284.     lea        Cyls(A5),A3            ;extract number of cylinders
  285.     move.l    #11,D0                    ;from item number 11
  286.     move.l    #MaxCylind,D3
  287.     jsr        ExtractNumb
  288.  
  289.     lea        RedWrtCur(A5),A3    ;extract reduced write current
  290.     move.l    #12,D0                    ;cylinder from item #12
  291.     move.l    Cyls(A5),D3
  292.     jsr        ExtractNumb
  293.  
  294.     lea        WrtPreComp(A5),A3    ;extract write precompensation
  295.     move.l    #13,D0                    ;cylinder from item #13
  296.     move.l    Cyls(A5),D3
  297.     jsr        ExtractNumb
  298.     
  299.     
  300. Exit
  301.     move.l    DialogPort(A5),-(A7)    ;pass pointer to Dialog rec
  302.     _CloseDialog                    ;close dialog box
  303.     jmp        EventLoop                ;return to event loop
  304.     EndProc
  305.  
  306. ; PROC EDefectProc
  307. ;
  308. ; Here we ask the user to enter the defects that are listed on
  309. ; the sheet that came with their disk drive.  They can enter as
  310. ; many as 60 defects.  Since our dialog box only has room for 12
  311. ; defects, we ask the user to hit the "More" button if they have
  312. ; additional defects.  We give the user a dialog box when they
  313. ; cannot enter any more defects.
  314. ;
  315. ; Register Ussage:
  316. ;    D0        Index for next item in dialog that is EditText that
  317. ;                we are going to remove a value from
  318. ;    D6        Index for record being input in defect list; index
  319. ;                is byte index of first field in record, not
  320. ;                actual record number
  321. EDefectProc    PROC    EXPORT
  322.  
  323.     clr.l    BadB_Num(A5)        ;clear global for # of defects
  324.  
  325. ; Clear our defect buffer.
  326.     move.l    #MaxBBListLen,D0    ;pass buffer size in D0
  327.     lea        BadB_List(A5),A0    ;pass address in A0
  328.     jsr        ClearBuff            ;go clear buffer
  329.     
  330.  
  331.  
  332. LoopForMore
  333.     clr.l    D6                    ;clear buffer record index
  334.  
  335.     clr.l    -(A7)                ;space for pointer to dialog rec
  336.     move.w    #EDefectsRN,-(A7)    ;Enter Defects Dialog resource #
  337.     pea        DialogBuff(A5)        ;pass pointer to dialog storage
  338.     move.l    #-1,-(A7)            ;make this window on top
  339.     _GetNewDialog                ;get dialog
  340.     
  341.     move.l    (A7),DialogPort(A5)    ;save pointer to dialog and
  342.                                     ;leave a copy on stack for 
  343.                                     ;call to _SetPort 
  344.     _SetPort
  345.     
  346.     lea        DialogBuff(A5),A4    ;pass address of dialog record
  347.     jsr        DefButton            ;outline default button
  348.      
  349.      
  350. NotYet
  351.     clr.l    -(A7)        ;use standard filter proc function
  352.     pea        ButtonHit(A5)    ;place for button hit
  353.     _ModalDialog            ;handle dialog events
  354.     cmpi.w    #3,ButtonHit(A5)            ;is "Cancel" button hit?
  355.     blt        EndDialog        ;no, "More" or "OK" buttons were hit
  356.     bgt        NotYet            ;no, not a button, get another event
  357.  
  358.  
  359. ; User hit "Cancel" button, so clear defect count and return
  360. ; go close dialog box
  361.     clr.l    BadB_Num(A5)    
  362.     bra        exit
  363.  
  364. ; We want to close up the dialog, but first we must extract the
  365. ; defect data that the user has entered.
  366. EndDialog
  367.     move.l    BadB_Num(A5),D6        ;move number of defects into D6
  368.     lsl.l    #4,D6                ;multiply by 16 to get byte 
  369.                                     ;index for first field in
  370.                                     ;next empty record
  371.     lea        BadB_List(A5),A0    ;A0 points 1st byte of buffer
  372.     
  373. AddToBuff
  374.     move.l    #3,D0                ;first item is 4, so put 3 in D0
  375.         
  376. LoopAddBuff
  377. ; First we extract the cylinder number.  We use the ExtractNumb
  378. ; procedure which takes the address for the result in A3, the 
  379. ; maximum value in D3 and the item number in D0.
  380.     
  381.     addq.l    #1,D0                ;increment D0 by 1, next item
  382.     lea        CylBBuff(A0,D6.L),A3
  383.     move.l    #MaxCylind,D3
  384.     jsr        ExtractNumb
  385.     
  386. ; Next we extract the head number
  387.     addq.l    #1,D0
  388.     lea        HeadBBuff(A0,D6.L),A3
  389.     move.l    #MaxHeads,D3
  390.     jsr        ExtractNumb
  391.     
  392. ; Lastly we extract the Bytes From Index value.
  393.     addq.l    #1,D0
  394.     lea        BFIBBuff(A0,D6.L),A3
  395.     move.l    #MaxBFI,D3
  396.     jsr        ExtractNumb
  397.  
  398. ; Test to see if the cylinder number was 0.  If so ignore this
  399. ; record as it was either empty or invalid.  Most controller
  400. ; cards cannot take defects in track 0.
  401.     tst.l    CylBBuff(A0,D6.L)    ;is cylinder value valid
  402.     bne        IncrCounters        ;yes increment counters
  403.  
  404. ; Otherwise, don't increment counters and next record will 
  405. ; overwrite this one which was invalid.
  406.     cmpi.l    #39,D0                ;have we reached the last item
  407.     beq        Exit                ;yes, go close dialog box
  408.     bra        LoopAddBuff            ;no, go extract next record
  409.     
  410. ; Cylinder number is not equal to 0 so this is a valid defect.
  411.  
  412. IncrCounters
  413.     cmpi.l    #(MaxBBs-1)*BadBRecLen,D6    ;is our buffer full
  414.     beq.s    Exit                    ;yes, so exit
  415.     
  416.     add.l    #BadBRecLen,D6            ;increment buffer index
  417.     cmpi.l    #39,D0
  418.     bne        LoopAddBuff
  419.     
  420. Exit
  421.     
  422.     lsr.l    #4,D6            ;byte count/16 = number of defects    
  423.     move.l    D6,BadB_Num(A5)    ;store defect number in global
  424.     move.l    DialogPort(A5),-(A7)    ;pass pointer to dialog
  425.     _CloseDialog            ;close up dialog
  426.  
  427.     cmpi.l    #60,BadB_Num(A5)    ;are there too many bad blocks
  428.     beq.s    NoMoreAlert            ;yes, go put up alert
  429.     
  430.     cmpi.l    #2,D5            ;did user hit "More" button (#2)
  431.     bne        ToEventLoop        ;no, so go to event loop
  432.     bra        LoopForMore        ;yes so put up dialog again
  433.  
  434. ToEventLoop
  435.     jmp        EventLoop
  436.  
  437. NoMoreAlert
  438.     move.w    #134,-(A7)        ;get our out of buffer space alert
  439.     clr.l    -(A7)            ;use standard filter proc function
  440.     _CautionAlert            ;use a caution alert
  441.     jmp        EventLoop
  442.     
  443.     EndProc
  444.  
  445. ; PROC FormatProc
  446. ;
  447. ; Formating procedure.  This is where we sent the drive 
  448. ; parameters in a Mode Select command.  We then send the drive
  449. ; defects with the Format Unit command.  And then the drive is
  450. ; ready to use with a driver installing program.
  451. FormatProc    PROC    EXPORT
  452.     IMPORT (HD_Select,HD_Discon,WriteDisk):CODE
  453.  
  454. ; First we put up a dialog box to make sure the user wants to 
  455. ; format the drive.
  456.  
  457. ; Make String buffer #1, 1 character long.  Then move the hex 
  458. ; value in the low order byte of Addr (the SCSI address of the
  459. ; target device) into the string buffer and convert it to ascii.
  460.     move.b    #1,StrBuff1(A5)    
  461.     move.b    1+Addr(A5),1+StrBuff1(A5)    
  462.     add.b    #$30,1+StrBuff1(A5)    
  463.     
  464.     clr.b    StrBuff2(A5)    ;clear all the other string buffers
  465.     clr.b    StrBuff3(A5)
  466.     clr.b    StrBuff4(A5)
  467.     pea        StrBuff1(A5)
  468.     pea        StrBuff2(A5)
  469.     pea        StrBuff3(A5)
  470.     pea        StrBuff4(A5)
  471.     _ParamText                ;substitute String buffer 1 for "^0"
  472.     
  473.     move.w    #132,-(A7)    ;get format alert dialog box
  474.     clr.l    -(A7)        ;use standard filter proc function
  475.     _CautionAlert
  476.     cmpi.w    #1,(A7)+    ;did user hit cancel?
  477.     bne        Exit        ;yes, so exit
  478.  
  479. ; User wants to Zap Drive, so let 'em have it!    First we 
  480. ; construct a data block to place parameters that we will send
  481. ; with the Mode Select command.
  482. ZapDrive
  483.  
  484. ; First we clear the data buffer
  485.     lea        ParamBuff(A5),A0    ;pass address of buffer
  486.     move.l    #ParamBuffLen,D0    ;pass length of buffer
  487.     jsr        ClearBuff            ;clear buffer
  488.     
  489.     clr.l    D0                    ;clear D0, used for scratch
  490. ; Header:
  491.     move.b    #8,$3(A0)            ;3rd byte = size of descriptor
  492.                                     ;list
  493.  
  494. ; Descriptor List:
  495.     move.b    #2,$A(A0)            ;high byte of sector size ($200)
  496.     
  497. ; Drive Parameter List:
  498.     move.b    #1,$C(A0)            ;List Format Code: (1 = soft
  499.                                     ;sectored drives, 2= hard
  500.                                     ;sectored drives or 
  501.                                     ;removable media drives)
  502.     
  503. ; Place word value of cylinder count into buffer.  We must do 
  504. ; this as two bytes because the wored in the output buffer is
  505. ; at an odd address
  506.     move.w    2+Cyls(A5),D0
  507.  
  508.     move.b    D0,$E(A0)        ;make sure $E(A0) has LSB
  509.     lsr.l    #8,D0            ;now move in high byte of word
  510.     move.b    D0,$D(A0)
  511.  
  512. ; Move byte value of head count into buffer.
  513.     move.b    3+Heads(A5),$F(A0)
  514.     
  515. ; Move word value of Reduced Write Current Cylinder into buffer.
  516.     move.w    2+RedWrtCur(A5),$10(A0)
  517.     
  518. ; Move word value of Write Precompensation Cylinder into buffer.
  519.     move.w    2+WrtPreComp(A5),$12(A0)
  520.     
  521. ; Move byte value of Step Pulse Code into Buffer.
  522.     move.b    1+stepcode(A5),$15(A0)
  523.     
  524. ; Now we send the Mode Select Command and the parameter buffer.
  525.     jsr        HD_Select        ;get SCSI bus and select drive
  526.     tst.w    Res(A5)            ;did we succeed?
  527.     bne        ToErrorProc        ;no, so go to error handling proc
  528.         
  529. ; Clear command buffer and construct command.
  530.     lea    CommandBuff(A5),A0    ;pass address of buffer
  531.     move.l    #CBuffLen,D0    ;pass length of buffer
  532.     jsr        ClearBuff        ;clear command buffer
  533.     
  534.     move.b    #ModeSelect,(A0)    ;move SCSI OP Code into byte #0
  535.     
  536.     move.b    #ModeSelBytesOut,4(A0)    ;move # of bytes to transfer
  537.                                         ;into byte #4
  538.     
  539.     clr.w    -(A7)            ;space for trap error code
  540.     move.l    A0,-(A7)        ;pass address of command buffer
  541.     move.w    #CommLenS,-(A7)    ;pass length of CDB (Command Data
  542.                                 ;Block), class 0 command, so it
  543.                                 ;is 6 bytes long
  544.     _SCSICmd                ;send command
  545.     
  546.     move.w    #ModeSelect,Last_Cmd(A5)    ;store command id 
  547.         
  548.     move.w    (A7)+,Res(A5)    ;did command work?
  549.     bne        ToErrorProc        ;no, go to error handling proc
  550.  
  551. ; Now we clear the pseudo program buffer and call the procedure
  552. ; WriteDisk to send the data to the controller card.
  553.     lea        PseudoProg(A5),A0    ;pass address of buffer
  554.     move.l    #PProgLen,D0        ;pass size of buffer
  555.     jsr        ClearBuff            ;clear buffer
  556.     
  557.     lea        ParamBuff(A5),A1    ;pass address of data buffer
  558.     move.l    #ModeSelBytesOut,D0    ;pass # of bytes to transfer
  559.     jsr        WriteDisk            ;send data
  560.  
  561.     move.l    #10,D0                ;pass number of ticks to wait
  562.     jsr        HD_Discon
  563.     tst.w    Res(A5)                ;SCSI Protocal Error?
  564.     bne        ToErrorProc
  565.     move.w    #ModeSelect,Last_Cmd(A5)
  566.     cmp.w    #$4,CompStat(A5)    ;is the Drive Not Ready?
  567.     beq        ToErrorProc            ;yes, go to error handling proc
  568.     cmp.w    #$24,CompStat(A5)    ;Was a bad parameter passed to
  569.                                     ;the controller?
  570.     beq        ToErrorProc            ;yes, go to error handling proc
  571.     
  572.     jsr        HD_Select            ;go get control of bus and 
  573.                                     ;select device
  574.     tst.w    Res(A5)                ;did we succeed
  575.     bne        ToErrorProc            ;no, go to error proc
  576.  
  577. ; Next, clear the buffer where we will assemble the CDB (Command
  578. ; Data Block).
  579.     lea        CommandBuff(A5),A0    ;pass address of buffer
  580.     move.l    #CBuffLen,D0        ;pass size of buffer
  581.     jsr        ClearBuff            ;clear buffer
  582.  
  583.     
  584.     move.b    #FormatUnit,(A0)    ;move op code into first byte
  585.     move.b    1+Interleave(A5),4(A0)    ;move byte value of inter
  586.                                         ;leave into byte 4
  587.     
  588.     tst.l    BadB_num(A5)        ;see if there are disk defects
  589.     beq        NoDefects            ;no, skip ahead
  590.     add.b    #$1C,1(A0)            ;place flags to tell controller
  591.                                     ;that defects are coming
  592. ; Call OutBuff to format defects so they can be read by
  593. ; controller card.
  594.     jsr        OutBuff                
  595.     
  596. NoDefects
  597.     clr.w    -(A7)                ;space for trap error code
  598.     move.l    A0,-(A7)            ;pass address of CDB
  599.     move.w    #CommLenS,-(A7)        ;class 0 command so pass length
  600.                                     ;of 6 bytes
  601.     _SCSICmd                    ;send command
  602.     
  603.     move.w    #FormatUnit,Last_Cmd(A5)    ;store command id
  604.         
  605.     move.w    (A7)+,Res(A5)        ;did _SCSICmd produce an error
  606.     bne        ToErrorProc            ;yes, go to error handling proc
  607.     
  608. ; If we are sending any info on disk defects, prepare buffer for
  609. ; pseudo program and pass count bytes and address to sending
  610. ; procedure.
  611.     tst.l    BadB_num(A5)        ;are we sending any defect data?
  612.     beq        NoPseudoProg        ;no, skip the next section
  613.  
  614. ; Clear pseudo program buffer.    
  615.     lea        PseudoProg(A5),A0    ;pass address of buffer
  616.     move.l    #PProgLen,D0        ;pass length of buffer
  617.     jsr        ClearBuff            ;clear buffer
  618.  
  619. ; Pass address of data, and number of bytes to be transfered. A0
  620. ; still contains the address of the pseudo program buffer.
  621.     lea        BadB_Out(A5),A1
  622.     move.l    BadB_Num(A5),D0        ;move number of defects to D0
  623.     lsl.l    #3,D0                ;multiply by 8 (8 bytes/defect)
  624.     addq.l    #4,D0                ;add 4 bytes for header
  625.     jsr        WriteDisk            ;send info on defects
  626.  
  627. NoPseudoProg
  628.     move.l    #MaxTicks,D0        ;pass number of ticks to wait
  629.     jsr        HD_Discon
  630.     tst.w    Res(A5)                ;SCSI Protocal Error?
  631.     bne        ToErrorProc            ;yes, go to error handling proc
  632.  
  633. ; Test Status byte from SCSI command to see if we passed a bad
  634. ; parameter or if there is a defect on track 0.
  635.     move.w    #FormatUnit,Last_Cmd(A5)    ;update command id for
  636.                                             ;error handling proc
  637.     cmp.w    #$24,CompStat(A5)    ;Was a bad parameter passed to 
  638.                                     ;the controller?
  639.     beq        ToErrorProc            ;yes, go to error proc
  640.     jmp        EventLoop    
  641.  
  642. Exit
  643.     jmp        EventLoop
  644.     
  645. ToErrorProc
  646.     jmp        ErrorProc
  647.     
  648.     EndProc
  649.  
  650. ; PROC ResetProc
  651. ;
  652. ; This procedure is called from the menu handling routine.  It
  653. ; acts as glue between the menu handling code and the reset 
  654. ; subroutine and allows us to use the reset subroutine elsewhere
  655. ; (like in SelAddrProc).
  656. ResetProc    PROC    EXPORT
  657.     IMPORT    (ResetDisk):CODE
  658.     
  659.     jsr        ResetDisk        ;go reset SCSI bus
  660.     tst.w    Res(A5)            ;test result
  661.     bne        ToErrorProc        ;if error go to error handling proc
  662.     jmp        EventLoop        ;else return to event loop
  663. ToErrorProc
  664.     jmp        ErrorProc
  665.     EndProc
  666.  
  667. ; PROC WriteDisk
  668. ;
  669. ; Procedure wor transfering data to the controller. This 
  670. ; routine uses a pseudo program which contains a simple loop of
  671. ; three instructions. This transfer could have been accomplished
  672. ; using only the first and the last instruction if we had put 
  673. ; the transfer count that is passed in D0 into the second 
  674. ; parameter of the first command. It would look exactly the 
  675. ; same if it were being used for a read, except the _SCSIWrite 
  676. ; trap would be replaced with _SCSIRead. Refer to IM volume IV 
  677. ; for info on the Pseudo instructions. Note each instruction is 
  678. ; a  word followed by two longword parameters.  SCSTOP must be 
  679. ; the last instruction. Address of pseudo buffer is passed in 
  680. ; A0.  Address of p_buff is passed in A1. Transfer count is 
  681. ; passed in D0.
  682. WriteDisk    PROC    ENTRY
  683.     movem.l    D0-D2/A0-A1,-(SP)    ;save registers
  684.  
  685. ; First command    moves bytes to given address
  686.     move.w    #SCINC,(A0)        
  687.     move.l    A1,2(A0)        ;address to be moved to or from
  688.     move.l    #1,6(A0)        ;transfer count in bytes
  689.  
  690. ; Second command is loop    
  691.     move.w    #SCLOOP,10(A0)    
  692.     move.l    #-10,12(A0)        ;rel addr
  693.     move.l    d0,16(A0)        ;loop count
  694.  
  695. ; Third command = stop, no parameters    
  696.     move.w    #SCSTOP,20(A0)    
  697.     
  698.     clr.w    -(SP)            ;space for trap result code (OSErr)
  699.     move.l    A0,-(SP)        ;address of pseudo program
  700.     
  701.     _SCSIWrite
  702.     move.w    (SP)+,Res(A5)    ;store result
  703.     move.w    #Write,Last_Cmd(A5)        ;store code for type of SCSI
  704.                                         ;command
  705.     
  706.     movem.l    (SP)+,D0-D2/A0-A1    ;restore registers
  707.     rts
  708.     ENDPROC
  709.     
  710. ; PROC HD_Select
  711. ;
  712. ; HD_Select tries to get control of the SCSI bus.  If it does,
  713. ; it then selects the device whose address is in Addr(A5).
  714.  
  715. HD_Select        PROC    ENTRY
  716.     IMPORT    CountOff:CODE
  717.     movem.l    D0-D2/A0-A1,-(A7)    ;save regs on stack
  718.     
  719.     clr.w    -(A7)                ;space for result code
  720.     _SCSIGet                    ;reserve the bus for our use
  721.     
  722.     move.w    (A7)+,Res(A5)        ;store result code
  723.     beq.s    ok                ;go to ok2 if we succeeded
  724.     move.w    #Get,Last_Cmd(A5)    ;else, store the last command
  725.     bra.s    exit                ;and return
  726.         
  727. ok
  728.     clr.w    -(A7)                ;space for result code
  729.     move.w    Addr(A5),-(A7)        ;load SCSI address of hard disk
  730.     _SCSISelect                    ;select device
  731.     
  732.     move.w    (A7)+,Res(A5)        ;store result code
  733.     move.w    #Select,Last_Cmd(A5)    ;store last command
  734.  
  735. exit
  736.     movem.l    (A7)+,D0-D2/A0-A1    ;restore registers
  737.     rts
  738.     ENDPROC
  739.  
  740.  
  741. ; PROC HD_Discon
  742. ;
  743. ; Here we complete a SCSI command.  We tell the Mac how long to
  744. ; wait for the target device on the SCSI bus to signal that the
  745. ; command has completed.  This procedure receives the number of
  746. ; ticks to wait in D0.
  747. HD_Discon    PROC    ENTRY
  748.     
  749.         movem.l    D0-D2/A0-A1,-(A7)    ;save regs on stack
  750.         
  751.         clr.w    CompStat(A5)
  752.         clr.w    CompMsg(A5)
  753.         
  754.         clr.w    -(A7)                ;space for result code
  755.         pea        CompStat(A5)        ;_SCSIComplete Status
  756.         pea        CompMsg(A5)            ;_SCSIComplete Message
  757.         move.l    D0,-(A7)            ;number of ticks to wait for
  758.                                         ;completion of the last
  759.                                          ;SCSI command
  760.         _SCSIComplete                                
  761.         move.w    (A7)+,Res(A5)    ;store result code
  762.         move.w    #Complete,Last_Cmd(A5)    ;store last command 
  763.         movem.l    (A7)+,D0-D2/A0-A1    ;restore registers
  764.         rts
  765.         ENDPROC
  766.  
  767. ; PROC InitGlobals
  768. ;
  769. ; Initialize the globals used to store information about the 
  770. ; hard disk.  Set all values to zero
  771. InitGlobals        PROC    EXPORT
  772.         
  773.         clr.w    Heads(A5)
  774.         clr.w    Cyls(A5)
  775.         clr.w    WrtPreComp(A5)
  776.         clr.w    RedWrtCur(A5)
  777.         clr.w    Interleave(A5)
  778.         clr.w    StepCode(A5)
  779.         clr.l    Addr(A5)
  780.  
  781.         clr.l    BadB_Num(A5)
  782.         
  783.         rts
  784.         ENDPROC
  785.  
  786. ; PROC ResetDisk
  787. ;
  788. ; This procedure resets the SCSI bus.  It has a one second delay
  789. ; after the reset because the CDC Wren III drives take more than
  790. ; 3/4 of a second to completely reset.  Other drives may need 
  791. ; longer delays after the reset.
  792. ResetDisk    PROC    EXPORT
  793.  
  794.     movem.l    D0-D2/A0-A1,-(A7)    ;save the registers
  795.     clr.w    -(A7)                ;space for result code
  796.     _SCSIReset                    ;reset the bus
  797.     move.w    (A7)+,Res(A5)        ;store results
  798.     beq.s    ok1                    ;go to ok1 if we succeeded
  799.     move.w    #Reset,Last_Cmd(A5)    ;else command code for error Msg
  800.     rts
  801.     
  802. ok1
  803.     move.l    #60,D0                ;D0 = number of ticks to wait
  804.     jsr        CountOff            ;jst to delay routine
  805.     
  806.     movem.l    (A7)+,D0-D2/A0-A1    ;restore the registers
  807.     rts
  808.     ENDPROC
  809.     
  810.     END